/**
 * @Author: Vincent
 * @Description:
 * @File:  AuthServices
 * @Version: 1.0.0
 * @Date: 2022/3/18 23:14
 */

package services

import (
	"TaskAssignmentSystem/internal/pkg/middleware/handler"
	Redis "TaskAssignmentSystem/pkg/db/redis"
	"TaskAssignmentSystem/pkg/timehandler"
	"TaskAssignmentSystem/pkg/utils"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/iris-contrib/middleware/jwt"
	"github.com/kataras/iris/v12"
	"time"
)

type AuthServiceInterface interface {
	New()

	JwtNew() *jwt.Middleware

	VerificationToken(ctx iris.Context) error

	ParseClaims(ctx iris.Context) (err error)

	SetToken(expTimeInt time.Duration) (tokenString string, err error)
}

type CustomClaims struct {
	CustomClaims jwt.MapClaims
	Config       jwt.Config `json:"config"`
	AppSecret    []byte     `json:"app_secret"`
	Id           uint       `json:"id"`
	UserName     string     `json:"user_name"`
	Type         int        `json:"type"`
}

func (c *CustomClaims) GetDateList(tRange *timehandler.TimeRange) (result []time.Time) {
	fmt.Println(tRange)
	panic("implement me")
}

func (c *CustomClaims) TimeHandle() (result *timehandler.TimeRange) {
	panic("implement me")
}

func (c *CustomClaims) CreateToken(id uint, userName, headPic string, userType string) (token string, err error) {
	fmt.Println(id, userName, headPic, userName, userType)
	return
}

func (c *CustomClaims) New() {
	c.CustomClaims = jwt.MapClaims{
		"id":        c.Id,
		"user_name": c.UserName,
		"type":      c.Type,
	}
}

func (c *CustomClaims) ParseClaims(ctx iris.Context) (err error) {
	tokenString := ctx.Values().Get("jwt").(*jwt.Token)
	claims := tokenString.Claims.(jwt.MapClaims)
	marshal, _ := json.Marshal(claims)
	err = json.Unmarshal(marshal, &c)
	if err != nil {
		//ReturnErrorHandler(StatusInternalServerError, ctx)
		return
	}
	return
}

// set token

func (c *CustomClaims) SetToken(expTimeInt time.Duration) (tokenString string, err error) {
	c.New()
	now := time.Now().In(utils.Loc)
	c.CustomClaims["iat"] = now.Unix()
	c.CustomClaims["exp"] = now.Add(expTimeInt).Unix()
	token := jwt.NewTokenWithClaims(jwt.SigningMethodHS256, &c.CustomClaims)
	//tokenString, err := token.SignedString(c.AppSecret)

	Redis.RedisGClient.Set(fmt.Sprintf("admin_token_%d", c.Id), c.AppSecret, expTimeInt)

	// Sign and get the complete encoded token as a string using the secret
	return token.SignedString(c.AppSecret)
}

func (c *CustomClaims) DelToken() error {
	return Redis.RedisGClient.Del(fmt.Sprintf("admin_token_%d", c.Id)).Err()
}

func (c *CustomClaims) JwtNew() *jwt.Middleware {
	return jwt.New(jwt.Config{
		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
			return c.AppSecret, nil
		},
		ErrorHandler: handler.JwtOnError,
		Expiration:   true,
		// Extract by the "token" url.
		// There are plenty of options.
		// The default jwt's behavior to extract a token value is by
		// the `Authorization: Bearer $TOKEN` header.
		Extractor: jwt.FromAuthHeader,
		// When set, the middleware verifies that tokens are
		// signed with the specific signing algorithm
		// If the signing method is not constant the `jwt.Config.ValidationKeyGetter` callback
		// can be used to implement additional checks
		// Important to avoid security issues described here:
		// https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
		SigningMethod: jwt.SigningMethodHS256,
		//Debug:         false,
	})
}

func (c *CustomClaims) VerificationToken(ctx iris.Context) error {
	if err := c.JwtNew().CheckJWT(ctx); err != nil {
		c.JwtNew().Config.ErrorHandler(ctx, errors.New("token已失效，请重新登陆!"))
		return err
	}
	return nil
}
